package com.zzyl.nursing.service.impl;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.IDCardUtils;
import com.zzyl.common.utils.PDFUtil;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.ai.BaiduQianfanAIModelUtil;
import com.zzyl.nursing.dto.HealthAssessmentDto;
import com.zzyl.nursing.vo.health.HealthReportVo;
import com.zzyl.oss.AliyunOSSOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.HealthAssessmentMapper;
import com.zzyl.nursing.domain.HealthAssessment;
import com.zzyl.nursing.service.IHealthAssessmentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;

import static com.zzyl.common.constant.CacheConstants.HEALTH_REPORT_KEY;
import static com.zzyl.common.constant.Constants.HEALTH_REPORT_PROMPT_TEMPLATE;

/**
 * 健康评估Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-09-11
 */
@Service
public class HealthAssessmentServiceImpl extends ServiceImpl<HealthAssessmentMapper, HealthAssessment> implements IHealthAssessmentService
{
    @Autowired
    private HealthAssessmentMapper healthAssessmentMapper;
    @Autowired
    private AliyunOSSOperator aliyunOSSOperator;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private BaiduQianfanAIModelUtil baiduUtil;

    /**
     * 查询健康评估
     * 
     * @param id 健康评估主键
     * @return 健康评估
     */
    @Override
    public HealthAssessment selectHealthAssessmentById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询健康评估列表
     * 
     * @param healthAssessment 健康评估
     * @return 健康评估
     */
    @Override
    public List<HealthAssessment> selectHealthAssessmentList(HealthAssessment healthAssessment)
    {
        return healthAssessmentMapper.selectHealthAssessmentList(healthAssessment);
    }

    /**
     * 新增健康评估
     * 
     * @param healthAssessmentDto 前端传入的健康评估信息
     * @return 成功信息和新增的这条数据的ID
     */
    @Override
    public Long insertHealthAssessment(HealthAssessmentDto healthAssessmentDto)
    {
        // 1.组装prompt提示词，根据身份证号，从Redis中读取体检内容
        String prompt = this.getPrompt(healthAssessmentDto.getIdCard());

        // 2.调用大模型分析体检报告，返回AI分析结果(JSON数据格式)
        String aiAnswer = this.baiduUtil.invoke(prompt);

        // 3.解析JSON格式的数据，将解析的结果保存到数据库
        HealthReportVo aiReport = JSONUtil.toBean(aiAnswer, HealthReportVo.class);
        Long id = this.saveHealthAssessment(aiReport, healthAssessmentDto);

        // 4.返回ID
        return id;
    }

    /**
     * 保存健康评估信息到数据库中
     * @param aiReport AI分析结果
     * @param formData 前端传入的评估信息
     * @return 新增的这条数据的ID
     */
    private Long saveHealthAssessment(HealthReportVo aiReport, HealthAssessmentDto formData) {
        HealthAssessment hs = new HealthAssessment();
        // 1.填充老人的基本信息
        hs.setElderName(formData.getElderName());
        String idCard = formData.getIdCard();
        hs.setIdCard(idCard);
        hs.setBirthDate(IDCardUtils.getBirthDateByIdCard(idCard));
        hs.setAge(IDCardUtils.getAgeByIdCard(idCard));
        hs.setGender(IDCardUtils.getGenderFromIdCard(idCard));
        // 2. 填充体检报告的基本信息
        hs.setTotalCheckDate(aiReport.getTotalCheckDate());
        hs.setPhysicalExamInstitution(formData.getPhysicalExamInstitution());
        hs.setPhysicalReportUrl(formData.getPhysicalReportUrl());
        // 3.填充老人的体检总结信息
        double score = aiReport.getHealthAssessment().getHealthIndex();
        hs.setHealthScore(String.valueOf(score));
        hs.setRiskLevel(aiReport.getHealthAssessment().getRiskLevel());
        hs.setSuggestionForAdmission(score > 60 ? 0 : 1);
        hs.setNursingLevelName(getNursingLevelNameByScore(score));
        hs.setAdmissionStatus(1);
        hs.setAssessmentTime(LocalDateTime.now());
        hs.setReportSummary(aiReport.getSummarize());
        // 3.填充疾病风险信息 & 健康指数信息 & 异常分析信息
        hs.setDiseaseRisk(JSONUtil.toJsonStr(aiReport.getRiskDistribution()));
        hs.setSystemScore(JSONUtil.toJsonStr(aiReport.getSystemScore()));
        hs.setAbnormalAnalysis(JSONUtil.toJsonStr(aiReport.getAbnormalData()));
        // 保存至数据库
        this.save(hs);
        return hs.getId();
    }

    private String getNursingLevelNameByScore(double score) {
        if (score < 0 || score > 100){
            throw new BaseException("体检报告异常，得分值超出范围");
        }
        if (score >= 90){
            return "三级护理";
        } else if (score >=80) {
            return "二级护理";
        } else if (score >=70) {
            return "一级护理";
        } else if (score >=60) {
            return "特技护理";
        }
        return "不建议入住";
    }

    /**
     * 组装prompt提示词
     * @param idCard 老人身份证
     * @return 提示词
     */
    private String getPrompt(String idCard) {
        // 1.先从Redis中查询体检报告结果、清除Redis中的体检报告
        String report = (String) redisTemplate.opsForHash().get(HEALTH_REPORT_KEY, idCard);

        // 2.组装提示词
        String prompt = StringUtils.format(HEALTH_REPORT_PROMPT_TEMPLATE, report);

        // 3.返回提示词
        return prompt;
    }

    /**
     * 修改健康评估
     * 
     * @param healthAssessment 健康评估
     * @return 结果
     */
    @Override
    public int updateHealthAssessment(HealthAssessment healthAssessment)
    {
        return updateById(healthAssessment) ? 1 : 0;
    }

    /**
     * 批量删除健康评估
     * 
     * @param ids 需要删除的健康评估主键
     * @return 结果
     */
    @Override
    public int deleteHealthAssessmentByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除健康评估信息
     * 
     * @param id 健康评估主键
     * @return 结果
     */
    @Override
    public int deleteHealthAssessmentById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    /**
     * 上传体检报告
     * @param idCardNo  老人身份证
     * @param file  上传的体检报告原文件
     * @return  封装了文件上传至阿里云后自动生成的URL等等信息的对象
     */
    @Override
    public String upload(String idCardNo, MultipartFile file) throws Exception {
        // 1.将文件上传至OSS
        String url = aliyunOSSOperator.upload(file.getBytes(), file.getOriginalFilename());
        // 2.读取PDF文件内容
        String pdfContent = PDFUtil.pdfToString(file.getInputStream());
        if (StrUtil.isBlank(pdfContent)){
            throw new BaseException("体检报告PDF文件内容为空");
        }
        // 3.将内容存储到Redis
        redisTemplate.opsForHash().put(HEALTH_REPORT_KEY, idCardNo, pdfContent);
        redisTemplate.expire(HEALTH_REPORT_KEY, Duration.ofMinutes(5));
        // 4.返回OSS生成的URL路径
        return url;
    }
}
